package io.light.frame.dal.mybatis.generator.core.meta;

import com.alibaba.druid.DbType;
import com.alibaba.druid.util.JdbcUtils;
import io.light.frame.dal.mybatis.generator.core.meta.visit.opt.H2_MysqlMetaOperations;
import io.light.frame.dal.mybatis.generator.core.meta.visit.opt.MetaOperations;
import io.light.frame.dal.mybatis.generator.core.meta.visit.opt.MysqlMetaOperations;
import io.light.frame.dal.mybatis.generator.core.util.GenToolKit;
import lombok.Getter;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ClassUtils;

import javax.sql.DataSource;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static io.light.frame.dal.mybatis.generator.core.meta.SupportedDialect.Holder.SUPPORTS;

/**
 * Supported dialect
 *
 * @author Ivan
 * @version 1.0.0
 * @date 2021-06-09 17:30
 */
public enum SupportedDialect implements Dialect {

    /**
     * MYSQL
     */
    MYSQL(MysqlMetaOperations.class),

    /**
     * MARIADB
     */
    MARIADB(MysqlMetaOperations.class),

    /**
     * H2_MYSQL
     */
    H2_MYSQL(H2_MysqlMetaOperations.class),
    ;

    /**
     * Dialect {@link MetaOperations}
     */
    @Getter
    private final MetaOperations metaOperations;

    SupportedDialect(Class<? extends MetaOperations> optClass) {
        Constructor<? extends MetaOperations> constructor = ClassUtils.getConstructorIfAvailable(optClass,
                Dialect.class);
        if (constructor != null) {
            metaOperations = BeanUtils.instantiateClass(constructor, this);
        } else {
            metaOperations = BeanUtils.instantiateClass(optClass);
        }
        register(this);
    }

    static class Holder {
        /**
         * Supported dialects holder
         */
        static final Map<String, Dialect> SUPPORTS = new HashMap<>();
    }

    public static Collection<Dialect> all() {
        return SUPPORTS.values();
    }

    public static void register(Dialect dialect) {
        SUPPORTS.put(dialect.name().toLowerCase(), dialect);
    }

    public static Dialect of(DataSource dataSource) {
        return GenToolKit.getDialect(dataSource);
    }

    public static Dialect of(String jdbcUrl) {
        DbType dbType = JdbcUtils.getDbTypeRaw(jdbcUrl, null);
        if (dbType == null) {
            return null;
        }
        if (dbType == DbType.h2) {
            String[] strArr = jdbcUrl.toLowerCase().trim().split(";");
            String mode = null;
            for (String kv : strArr) {
                if (kv.startsWith("mode=")) {
                    mode = kv.replace("mode=", "");
                    break;
                }
            }
            if (mode == null) {
                return null;
            }
            return SUPPORTS.get(dbType.name().toLowerCase() + "_" + mode);
        }
        return SUPPORTS.get(dbType.name().toLowerCase());
    }
}
